package org.rency.crawler.fetch.processor.impl;

import javax.annotation.Resource;
import org.apache.commons.lang.StringUtils;
import org.rency.common.utils.tool.Profiler;
import org.rency.crawler.common.enums.ReturnCode;
import org.rency.crawler.common.exception.CrawlerIllegalException;
import org.rency.crawler.common.helper.GeneratorHelper;
import org.rency.crawler.common.helper.MDCHelper;
import org.rency.crawler.common.helper.ValidatorHelper;
import org.rency.crawler.domain.FetchExtension;
import org.rency.crawler.domain.FetchRequest;
import org.rency.crawler.domain.FetchResponse;
import org.rency.crawler.fetch.handler.FetchHandler;
import org.rency.crawler.fetch.helper.FetchCarrier;
import org.rency.crawler.fetch.helper.FetchHelper;
import org.rency.crawler.fetch.processor.FetchProcessor;
import org.rency.crawler.fetch.state.FetchStateCarrier;
import org.rency.crawler.fetch.state.FetchStateFactory;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;

/**
 * 描述: ${TODO}<br>
 * 最近修改时间:2017/11/23 9:43<br>
 *
 * @author CaiyuRen
 * @version V1.0
 * @since 2017/11/23 9:43
 */
@Service
public class FetchProcessorImpl implements FetchProcessor {

  private static final Logger logger = LoggerFactory.getLogger(FetchProcessorImpl.class);

  @Resource
  private FetchStateFactory fetchStateFactory;

  @Override
  public FetchResponse fetch(FetchRequest request) {
    return this.fetch(request,null);
  }

  @Override
  public FetchResponse fetch(FetchRequest request, FetchExtension extension) {
    logger.info("抓取请求:{}.",request);
    FetchResponse response = this.validation(request);
    if(!response.getSuccess()){
      return response;
    }
    FetchCarrier carrier = new FetchCarrier(request,extension);
    carrier.setFetchState(fetchStateFactory.getStateStar());
    return this.handlerChain(carrier);
  }

  /**
   * 请求参数校验
   * @param request
   * @return
   */
  private FetchResponse validation(FetchRequest request){
    logger.debug("抓取请求参数校验:{}.",request);
    try{
      ValidatorHelper.notNull(request, "抓取请求");
      ValidatorHelper.validator(request);
      if(StringUtils.isBlank(request.getFetchNo())){
        String fullURL = FetchHelper.appendParam2URL(request.getFetchUri(),request.getParameter());
        request.setFetchNo(GeneratorHelper.genHashCode(fullURL));
      }
    }catch (CrawlerIllegalException e){
      logger.error("抓取请求参数校验失败:{}.",e);
      return FetchResponse.fail(ReturnCode.ILLEGAL_VALID,e.getDetailMessage());
    }finally {
      logger.debug("抓取请求参数校验完成");
    }
    return FetchResponse.success(ReturnCode.SUCCESS);
  }

  private FetchResponse handlerChain(FetchCarrier carrier){
    MDCHelper.put(carrier.getRequest().getFetchNo(),carrier.getRequest().getFetchUri());
    logger.info("开始执行抓取:{}.",carrier.getRequest().getFetchUri());
    Profiler.start(carrier.getRequest().getFetchNo());
    long starTime = System.currentTimeMillis();
    try{
      FetchStateCarrier nextState = null;
      while(true){
        FetchHandler handler = carrier.getFetchState().getFsService();
        Profiler.enter(carrier.getFetchState().getFsCode()+". "+handler.getName());
        try {
          /**
           * 处理器进行处理
           */
          handler.handler(carrier);
          /**
           * 将当前状态机加入历史
           */
          carrier.addFetchStateHistory(carrier.getFetchState());
          /**
           * 获取下一状态机
           */
          nextState = fetchStateFactory.getNextState(carrier.getFetchState().getFsCode(),carrier.getFetchState().getFsStatus());
          if(nextState == null) {
            break;
          }
          /**
           * 将当前状态设置为下一状态
           */
          carrier.setFetchState(nextState);
        }finally {
          Profiler.release();
        }
      }
    }finally {
      logger.info("抓取流程结束,耗时:{}ms,目标:{}.",(System.currentTimeMillis() - starTime),carrier.getRequest().getFetchUri());
      logger.info("抓取时间分析:{}",Profiler.dump());
      Profiler.reset();
      MDCHelper.clear();
    }
    return carrier.getResponse();
  }

}
